home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OCFSRC.PAK / APPDESC.CPP next >
C/C++ Source or Header  |  1997-05-06  |  27KB  |  984 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1997 by Borland International, All Rights Reserved
  4. //
  5. // $Revision:   2.14  $
  6. //
  7. // Application class factory and type library implementation
  8. //----------------------------------------------------------------------------
  9. #include <ocf/pch.h>
  10. #if !defined(OCF_APPDESC_H)
  11. # include <ocf/appdesc.h>
  12. #endif
  13. #if !defined(OCF_OCREG_H)
  14. # include <ocf/ocreg.h>
  15. #endif
  16. #if !defined(CLASSLIB_CMDLINE_H)
  17. # include <classlib/cmdline.h>
  18. #endif
  19. #if !defined(CLASSLIB_OBJSTRM_H)
  20. # include <classlib/objstrm.h>
  21. #endif
  22. #include <strstrea.h>
  23.  
  24. DIAG_DECLARE_GROUP(OcDll);
  25.  
  26. static TLangId ParseLangId(const char* text);
  27.  
  28. //----------------------------------------------------------------------------
  29. // TAppDescriptor implementation
  30. //
  31.  
  32. // Provides access to the AppDescriptor of this component
  33. //
  34. TAppDescriptor* TAppDescriptor::This = 0;
  35.  
  36. //
  37. //
  38. //
  39. TAppDescriptor::TAppDescriptor(TRegList& regInfo, TComponentFactory callback,
  40.                                string& cmdLine, HINSTANCE hInst,
  41.                                const TRegLink* linkHead)
  42. :
  43.   AppClassId(regInfo), RegInfo(regInfo),
  44.   AppInstance (hInst), LinkHead(linkHead),
  45.   FactoryCallback(callback)
  46. {
  47.   Init(0);
  48.   ProcessCmdLine(cmdLine);
  49. }
  50.  
  51. //
  52. //
  53. //
  54. void
  55. #if defined(BI_PLAT_WIN16)
  56. TAppDescriptor::Init(IMalloc* alloc)
  57. #else
  58. TAppDescriptor::Init(IMalloc*)
  59. #endif
  60. {
  61.   AppProgId= &RegInfo.LookupRef("progid");
  62.   AppName  = &RegInfo.LookupRef("appname");
  63.   AppDoc   = &RegInfo.LookupRef("description");
  64.   HelpFile = &RegInfo.LookupRef("typehelp");
  65.  
  66.   // Provide direct access for destructors from component main module
  67.   //
  68.   This = this;
  69.   RegClassHdl = RegObjectHdl = ClassCount = LinkGuidCount = 0;
  70.   DebugGuidOffset = LinkGuidOffset = LibGuidOffset = 0;
  71.   ServedList = ActiveObject = 0;
  72.   RefCnt = 0;
  73.   LockCount = 0;
  74.   TypeLib = 0;
  75.   Options = 0;
  76.   ClassList = 0;
  77.   //-------
  78.   Creator = 0;
  79.  
  80.   // Determine if we are running an EXE or a DLL, initialize OLE if an EXE
  81.   //
  82. #if defined(BI_PLAT_WIN16)
  83.   if ((unsigned)AppInstance + 1 == _SS) { // check instance handle for EXE
  84.     Options = amExeModule | amExeMode;
  85.     OLECALL(OleInitialize(alloc), "OleInitialize");
  86.   }
  87. #else
  88.   if (::GetModuleHandle(0) == AppInstance) { // check instance handle for EXE
  89.     Options = amExeModule | amExeMode;
  90.     OLECALL(OleInitialize(0), "OleInitialize");
  91.   }
  92. #endif
  93.  
  94.   // Set the initial usage mode based on the reglist entry and module type
  95.   // NOTE: InProc servers are multiple-user
  96.   //
  97.   if (Options & amExeModule) {
  98.     const char* usage = RegInfo.Lookup("usage");
  99.     char su[] = ocrSingleUse;
  100.     if (usage && *usage == *su)
  101.       Options |= amSingleUse;
  102.   }
  103.  
  104.   // Set the app language to the one in the reglist if provided
  105.   //
  106.   const char* regLang = RegInfo.Lookup("language");
  107.   AppLang = regLang ? ParseLangId(regLang) : TLocaleString::UserDefaultLangId;
  108.  
  109.   // Lookup the version, providing a default of 1.0
  110.   //
  111.   Version = RegInfo.Lookup("version", AppLang);
  112.   if (!Version)
  113.     Version = "1.0";
  114.  
  115.   // Assign GUID for debug registration
  116.   // Check if alternate debug registration has been provided and allocated GUID
  117.   //
  118.   if ((Options & amExeModule) && RegInfo.Lookup("debugprogid"))
  119.     DebugGuidOffset = AppClassId.AllocId();
  120.  
  121.   // Generate array of all automated classes and assign GUIDs
  122.   //
  123.   MergeAutoClasses();
  124. }
  125.  
  126. //
  127. //
  128. //
  129. TAppDescriptor::~TAppDescriptor()
  130. {
  131.   UnregisterClass();
  132.   delete TypeLib;
  133.   delete[] ClassList;
  134.   This = 0;
  135.  
  136.   // Following should not normally happen - but just in case
  137.   //
  138.   if (RefCnt > 0)
  139.     ::CoDisconnectObject(this,0);
  140.  
  141.   // And last, uninitialize OLE
  142.   //
  143.   if (Options & amExeModule)
  144.     ::OleUninitialize();
  145. }
  146.  
  147. // Creates a TServedObject helper object which implements an IDispatch
  148. // implementation on behalf of the 'Application' object.
  149. //
  150. TUnknown*
  151. TAppDescriptor::CreateAutoApp(TObjectDescriptor objDesc, uint32 options,
  152.                               IUnknown* outer)
  153. {
  154.   if (objDesc.Destruct == TObjectDescriptor::Delete) {
  155.     if (!(options & (amServedApp | amAutomation)))
  156.       objDesc.Destruct = TObjectDescriptor::Quiet;
  157.     else if (options & amExeMode)
  158.       objDesc.Destruct = TObjectDescriptor::PostQuit;
  159.   }
  160.  
  161.   // NOTE: Creator is destroyed via delegation
  162.   //
  163.   Creator = new TServedObjectCreator(*this);
  164.  
  165.   // NOTE : Object is created with ref. count of '0'
  166.   //
  167.   TUnknown* obj = Creator->CreateObject(objDesc, outer);
  168.  
  169.   // NOTE: OLE's 'RegisterActiveObject' will do an 'AddRef()'
  170.   //
  171.   RegisterObject(objDesc);
  172.  
  173.   // NOTE: Object will be RefCnt++ when aggregated or converted to IUnknown*
  174.   //
  175.   return obj;
  176. }
  177.  
  178. // Releases the helper object (TServedObject) implementing IDispatch on behalf
  179. // of the 'Application' object.
  180. //
  181. void
  182. TAppDescriptor::ReleaseAutoApp(TObjectDescriptor app)
  183. {
  184.   TServedObject* obj;
  185.   if (ActiveObject && (obj = FindServed(app)) != 0 && obj == ActiveObject)
  186.     UnregisterObject();
  187. }
  188.  
  189. // Creates a TServedObject helper which implements IDispatch on behalf of
  190. // the class described via the 'objDesc' parameter.
  191. // NOTE: The returned object initial ref. count is '0'.
  192. //
  193. TUnknown*
  194. TAppDescriptor::CreateAutoObject(TObjectDescriptor objDesc, TServedObject& app,
  195.                                  IUnknown* outer)
  196. {
  197.   return app.Creator.CreateObject(objDesc, outer);
  198. }
  199.  
  200. // Creates a TServedObject helper which implements IDispatch on behalf of the
  201. // class instance passed in via 'obj' and 'objInfo' parameters.
  202. //
  203. TUnknown*
  204. TAppDescriptor::CreateAutoObject(const void* obj, const typeinfo& objInfo,
  205.                                  const void* app, const typeinfo& appInfo,
  206.                                  IUnknown* outer)
  207. {
  208.   TServedObject* autoApp = FindServed(MostDerived(app, appInfo));
  209.   TServedObjectCreator *creator = autoApp ? &(autoApp->Creator) : Creator;
  210.   if (!creator) {
  211.     // NOTE: Destroyed through delegation
  212.     //
  213.     Creator = new TServedObjectCreator(*this);
  214.     creator = Creator;
  215.   }
  216.  
  217.   TAutoClass::TAutoClassRef* ref = ClassList;
  218.   for (int i = 0; i < ClassCount; i++, ref++)
  219.     if (objInfo == ref->Class->TypeInfo)
  220.       return creator->CreateObject(TObjectDescriptor(obj, *ref->Class), outer);
  221.   return 0;
  222. }
  223.  
  224. // QueryInterface: Hands out IUnknown or IClassFactory
  225. //
  226. HRESULT _IFUNC
  227. TAppDescriptor::QueryInterface(const IID& riid, void** retIface)
  228. {
  229.   if (riid == IID_IUnknown || riid == IID_IClassFactory) {
  230.     AddRef();
  231.     *retIface = (IUnknown*)this;
  232.     return HR_NOERROR;
  233.   }
  234.   *retIface = 0;
  235.   return HR_NOINTERFACE;
  236. }
  237.  
  238. // Usual IUnknown 'AddRef'
  239. //
  240. ulong _IFUNC
  241. TAppDescriptor::AddRef()
  242. {
  243.   return ++RefCnt;
  244. }
  245.  
  246. // Usual IUnknown 'Release'
  247. // NOTE: This object does *NOT* delete itself
  248. //
  249. ulong _IFUNC
  250. TAppDescriptor::Release()
  251. {
  252.   return --RefCnt;
  253. }
  254.  
  255. //
  256. //
  257. //
  258. HRESULT _IFUNC
  259. TAppDescriptor::CreateInstance(IUnknown* outer, const IID& riid,
  260.                                void** ppv)
  261. {
  262.  
  263. #if   0  
  264.  
  265.   // Display which interface is being asked for
  266.   //
  267.   const char* p = OCFStringFromIID(riid);
  268.  
  269.   TOcOleCtl* oleCtl = new TOcOleCtl(outer);
  270.   return SUCCEEDED(oleCtl->QueryInterface(riid, ppv));
  271.  
  272. #else
  273.  
  274.   *ppv = 0;
  275.   IUnknown* obj;
  276.   if (!FactoryCallback)
  277.     return HR_FAIL;
  278.  
  279.   try {
  280.     // Test for special condition to force run DLL as an EXE
  281.     //
  282.     if (outer && outer->QueryInterface(IID_NULL, ppv) == HR_NOERROR)
  283.       obj = FactoryCallback(0, Options | amServedApp | amExeMode | amRun);
  284.     else
  285.       obj = FactoryCallback(outer, Options | amServedApp);
  286.     if (!obj)
  287.       return HR_FAIL;
  288.     if (Options & amSingleUse)
  289.       UnregisterClass();
  290.  
  291.     // Cannot return outer if aggregated
  292.     //
  293.     if (riid == IID_IUnknown) {
  294.       *ppv = obj;
  295.       return HR_OK;
  296.     }
  297.     HRESULT stat = obj->QueryInterface(riid, ppv);
  298.     obj->Release();
  299.     return stat;
  300.   }
  301.   catch (...) {
  302.     // NOTE: Cannot throw any exception through OLE
  303.     //       We'll assume a resource problem;
  304.     //       Is there a better error code to express an exception ??
  305.     //
  306.     return HR_OUTOFMEMORY;
  307.   }
  308.  
  309. #endif
  310. }
  311.  
  312. // LockServer [IClassFactory]
  313. //
  314. HRESULT _IFUNC
  315. TAppDescriptor::LockServer(int lock)
  316. {
  317.   if (lock)
  318.     LockCount++;
  319.   else {
  320.     // NOTE: Should we notify app when count reaches 0?
  321.     //
  322.     LockCount--;
  323.   }
  324.  
  325.   TRACEX(OcDll, 1, "LockServer(" << lock << ") Count:" << LockCount);
  326.  
  327.   return HR_NOERROR;
  328. }
  329.  
  330. // Returns version as a whole number
  331. //
  332. uint16
  333. TAppDescriptor::GetVersionField(unsigned field)
  334. {
  335.   const char* cp = Version;
  336.   char c;
  337.   while (field--) {
  338.     while ((c = *cp++) != '.') {
  339.       if (c < '0' || c > '9')
  340.         return 0;    // terminate on null or invalid digit
  341.     }
  342.   }
  343.   uint16 ver = 0;
  344.   while ((c = *cp++) >= '0' && c <= '9')
  345.     ver = uint16(ver * 10 + c - '0');
  346.   return ver;
  347. }
  348.  
  349.  
  350. // Register an EXE class object with OLE so that other applications can connect to it
  351. //
  352. void
  353. TAppDescriptor::RegisterClass()
  354. {
  355.   int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
  356.   if (!RegClassHdl) {
  357.     OLECALL(::CoRegisterClassObject(AppClassId[guidOffset], this,
  358.                                     CLSCTX_LOCAL_SERVER,
  359.                                     (Options & amSingleUse) ? REGCLS_SINGLEUSE :
  360.                                                               REGCLS_MULTIPLEUSE,
  361.                                     &RegClassHdl),
  362.                                     "Register App class");
  363.   }
  364. }
  365.  
  366. // Invalidates application class registered earlier with 'RegisterClass'
  367. //
  368. void
  369. TAppDescriptor::UnregisterClass()
  370. {
  371.   if (RegClassHdl) {
  372.     OLECALL(::CoRevokeClassObject(RegClassHdl), "Unregister App class");
  373.     RegClassHdl = 0;
  374.   }
  375. }
  376.  
  377. // Registers the helper object (TServedObject) of the class described via
  378. // the 'app' parameter as the active object for its classId.
  379. //
  380. bool
  381. TAppDescriptor::RegisterObject(TObjectDescriptor app)
  382. {
  383.   if (ActiveObject)
  384.     return false;
  385.   TServedObject* obj = FindServed(app);
  386.   if (!obj)
  387.     return false;
  388.   int guidOffset = IsOptionSet(amDebug) ? DebugGuidOffset : 0;
  389.  
  390.   // Refcnt may be zero, protect against AddRef/Release
  391.   //
  392.   obj->AdjustRefCount(+1);
  393.  
  394.   // Register object with Ole. OLE 2.02 suggests ACTIVEOBJECT_WEAK, but that
  395.   // does not appear to provide adequate locking.
  396.   //
  397.   OLECALL(::RegisterActiveObject(&(IUnknown&)*obj,
  398.                                  AppClassId[guidOffset],
  399.                                  ACTIVEOBJECT_STRONG,
  400.                                  &RegObjectHdl),
  401.           "Register App as active");
  402.  
  403.   obj->AdjustRefCount(-1);
  404.   ActiveObject = obj;
  405.   return true;
  406. }
  407.  
  408. // Invalidates a helper object registers with RegisterObject earlier
  409. //
  410. void
  411. TAppDescriptor::UnregisterObject()
  412. {
  413.   if (RegObjectHdl) {
  414.     // NOTE: Zero before OLE call in case obj. destructor is invoked
  415.     //
  416.     ActiveObject = 0;
  417.     OLECALL(::RevokeActiveObject(RegObjectHdl, 0), "Unregister App");
  418.     RegObjectHdl = 0;
  419.   }
  420. }
  421.  
  422. // Returns the index of a 'TAutoClass' instance
  423. //
  424. int
  425. TAppDescriptor::GetClassIndex(TAutoClass* cls)
  426. {
  427.   TAutoClass::TAutoClassRef* ref = ClassList;
  428.   for (int index = 0; index < ClassCount; ref++, index++) {
  429.     if (ref->Class == cls)
  430.       return index;
  431.   }
  432.   return -1;
  433. }
  434.  
  435. // Retrieves the GUID of the specified TAutoClass instance.
  436. // NOTE: Passing '0' as the 'cls' return the GUID of the type Library.
  437. // Returns 'true' if successful, or 'false' otherwise.
  438. //
  439. bool
  440. TAppDescriptor::GetClassId(TAutoClass* cls, GUID& retId)
  441. {
  442.   int offset;
  443.   if (cls) {
  444.     int index = GetClassIndex(cls);
  445.     if (index == -1)
  446.       return false;
  447.     offset = ClassList[index].GuidOffset;
  448.   } else {
  449.     offset = LibGuidOffset;
  450.   }
  451.   retId = AppClassId[offset];
  452.   return true;
  453. }
  454.  
  455. // Returns the GUID allocated as the specified index.
  456. // NOTE: Will allocate a new GUID if 'index' has not been allocated yet.
  457. //
  458. TClassId
  459. TAppDescriptor::GetLinkGuid(int index)
  460. {
  461.   while (index >= LinkGuidCount) {
  462.     int id = AppClassId.AllocId();
  463.     if (!LinkGuidOffset)
  464.       LinkGuidOffset = id;
  465.     LinkGuidCount++;
  466.   }
  467.   return AppClassId[LinkGuidOffset + index];
  468. }
  469.  
  470. // Returns the TAutoClass instance as the specified index.
  471. //
  472. TAutoClass*
  473. TAppDescriptor::GetAutoClass(unsigned index)
  474. {
  475.   if (index >= ClassCount)
  476.     return 0;
  477.   return ClassList[index].Class;
  478. }
  479.  
  480. // Returns the TAutoClass instance assigned the specified GUID.
  481. //
  482. TAutoClass*
  483. TAppDescriptor::GetAutoClass(const GUID& clsid)
  484. {
  485.   int offset = AppClassId.GetOffset(clsid);
  486.   if (offset != -1) {
  487.     TAutoClass::TAutoClassRef* ref = ClassList;
  488.     for (int count = ClassCount; count--; ref++) {
  489.       if (ref->GuidOffset == offset)
  490.         return ref->Class;
  491.     }
  492.   }
  493.   return 0;
  494. }
  495.  
  496. // Get the document template with the given GUID
  497. //
  498. TRegLink*
  499. TAppDescriptor::GetRegLink(const GUID far& clsid)
  500. {
  501.   int linkGuidIndex = 0;
  502.   for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  503.     TRegList& regList = link->GetRegList();
  504.     if (regList["progid"]) {
  505.       const char* id = regList["clsid"];
  506.       if (!id) {
  507.         if (clsid == (GUID&)GetLinkGuid(linkGuidIndex++))
  508.           return const_cast<TRegLink*>(link);
  509.       }
  510.       else {
  511.         TClassId classId(id);
  512.         if (clsid == (GUID&) classId)
  513.           return const_cast<TRegLink*>(link);
  514.       }
  515.     }
  516.   }
  517.  
  518.   return 0;
  519. }
  520.  
  521. // Returns the 'ITypeLib' interface pointer describing the objects exposed by
  522. // this instance of 'TAppDescriptor'.
  523. //
  524. ITypeLib*
  525. TAppDescriptor::GetTypeLibrary()
  526. {
  527.   if (!ClassCount)
  528.     return 0;
  529.   if (!TypeLib) {
  530.     TypeLib = new TTypeLibrary(*this, AppLang);
  531.   }
  532.   ((IUnknown&)*TypeLib).AddRef();
  533.   return TypeLib;
  534. }
  535.  
  536. //----------------------------------------------------------------------------
  537. // TServedObject list management
  538. //
  539.  
  540. //
  541. //
  542. //
  543. TServedObject*
  544. TAppDescriptor::FindServed(const void far* mostDerivedObj)
  545. {
  546.   TServedObject* p = ServedList;
  547.   for (; p; p = p->Next)
  548.     if (p->RootObject == mostDerivedObj)
  549.       break;
  550.   return p;
  551. }
  552.  
  553. //
  554. //
  555. //
  556. TServedObject*
  557. TAppDescriptor::FindServed(TObjectDescriptor& objDesc)
  558. {
  559.   if (objDesc.Object)
  560.     return FindServed(objDesc.MostDerived());
  561.   for (TServedObject* p = ServedList; p; p = p->Next)
  562.     if (p->Object == 0 && p->Class == objDesc.Class)
  563.       return p;
  564.   return 0;
  565. }
  566.  
  567. //
  568. //
  569. //
  570. void
  571. TAppDescriptor::AddServed(TServedObject& obj) {
  572.   if (ServedList)
  573.     ServedList->Prev = &obj.Next;
  574.   obj.Next = ServedList;
  575.   obj.Prev = &ServedList;
  576.   ServedList = &obj;
  577. }
  578.  
  579. //
  580. //
  581. //
  582. void
  583. TAppDescriptor::RemoveServed(TServedObject& obj) {
  584.   *obj.Prev = obj.Next;
  585.   if (obj.Next)
  586.     obj.Next->Prev = obj.Prev;
  587. }
  588.  
  589. //
  590. //
  591. //
  592. void
  593. TAppDescriptor::FlushServed() {
  594.   while (ServedList)
  595.     delete ServedList;
  596. }
  597.  
  598. //
  599. //
  600. //
  601. void
  602. TAppDescriptor::InvalidateObject(const void far* obj)
  603. {
  604.   TServedObject* p = FindServed(obj);
  605.   if (p) {
  606.     p->RootObject = 0;
  607.     p->Object = 0;
  608.   }
  609. }
  610.  
  611. //
  612. //
  613. //
  614. void
  615. TAppDescriptor::ReleaseObject(const void far* obj)
  616. {
  617.   TServedObject* p = FindServed(obj);
  618.   if (p) {
  619.     p->RootObject = 0;
  620.     p->Object = 0;
  621.     ((IUnknown&)*p).Release();   // destructs if no external connections
  622.   }
  623. }
  624.  
  625. //
  626. //
  627. //
  628. ITypeInfo*
  629. TAppDescriptor::CreateITypeInfo(TAutoClass& cls)
  630. {
  631.   TServedObjectCreator& creator = ServedList ? ServedList->Creator
  632.                                              : *new TServedObjectCreator(*this);
  633.   TUnknown* obj = creator.CreateObject(TObjectDescriptor(0, cls));
  634.   IUnknown& unk = (IUnknown&)*obj;
  635.   ITypeInfo* typeInfo = 0;
  636.   unk.QueryInterface(IID_ITypeInfo, (void far* far*) &typeInfo);
  637.   return typeInfo;
  638. }
  639.  
  640. //
  641. // Parse command line for Ole flags.
  642. // Check for [-/] and remove options that are found. Gets option arguments
  643. // and performs any immediate option actions
  644. //
  645. void
  646. TAppDescriptor::RegisterServer(TLangId lang, const char* regFilename)
  647. {
  648.   try {
  649.     TRegItem regDebug[DebugRegCount];
  650.  
  651.     // Check if registration output to Registry or to user-specified reg file
  652.     //
  653.     char guidStr[40];
  654.     strstream regStrm;
  655.     ostream* strm = ®Strm;
  656.     bool alwaysReg = IsOptionSet(amRegServer);
  657.     ofstream  fileStrm;
  658.     if (regFilename) {
  659.       fileStrm.open(regFilename);
  660.       if (!fileStrm.good())
  661.         throw TXRegistry(regFilename, "file");
  662.       strm = &fileStrm;
  663.       fileStrm << "REGEDIT\n";  // write registration file header
  664.       alwaysReg = true;
  665.     }
  666.     SetOption(amUnregServer, false);// cancel unregister on reregister
  667.  
  668.     // Make sure that the app reginfo is in the registry
  669.     //
  670.     bool forceReg = alwaysReg;
  671.     if (AppProgId) {       // don't attempt register app if no progid reg key
  672.       if (!forceReg) {
  673.         strstream vstrm;
  674.         NS_OCF::OcRegisterClass(
  675.           RegInfo, AppInstance, vstrm, lang, "\001\002\006");
  676.         if (::OcRegistryValidate(vstrm) != 0)
  677.           forceReg = true;
  678.       }
  679.       if (forceReg) {
  680.         char* debugGuid = 0;
  681.         if (DebugGuidOffset) {                // setup reg item for debug reg
  682.           TClassId debugClsid(AppClassId[DebugGuidOffset]);
  683.           strcpy(guidStr, debugClsid);
  684.           debugGuid = guidStr;
  685.           if (::OcSetupDebugReg(RegInfo, regDebug, lang, debugGuid)) {
  686.             NS_OCF::OcRegisterClass(
  687.               RegInfo, AppInstance, *strm, lang, 0, 0, OcRegNoDebug);
  688.             NS_OCF::OcRegisterClass(
  689.               RegInfo, AppInstance, *strm, lang, AppDebugFilter, 0, regDebug);
  690.           }
  691.           else {
  692.             debugGuid = 0;  // if debug registration fails, use normal
  693.           }
  694.         }
  695.         if (!debugGuid)
  696.           NS_OCF::OcRegisterClass(RegInfo, AppInstance, *strm, lang, 0, 0,
  697.                             (Options & amExeModule) ? 0 : OcRegNotDll);
  698.       }
  699.     }
  700.  
  701.     // Write templates to registration file as needed
  702.     //
  703.     int linkGuidIndex = 0;
  704.     TRegItem regAppName[2] = {{"appname",{RegInfo["appname"]}}, {0,{0}}};
  705.     for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  706.       TRegList& regList = link->GetRegList();
  707.       if (regList["progid"]) {
  708.         char guidStr[40];
  709.         int debugStat = (Options & amExeModule) ?
  710.                         NS_OCF::OcSetupDebugReg(regList, regDebug, lang,
  711.                                                 guidStr) : 0;
  712.         TRegItem regClsid[3] = {{"debugger",{""}}, {"clsid",{guidStr}}, {0,{0}}};
  713.         TRegItem* clsInfo = regClsid;
  714.         if (!debugStat && Options & amExeModule)
  715.           clsInfo++;     // no cancel debugger if no debugprogid
  716.         if (!regList["clsid"]) {      // check if GUID needs to be assigned
  717.           TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  718.           strcpy(guidStr, linkClsid);
  719.         }
  720.         else {
  721.           regClsid[1].Key = 0;  // shorten list to exclude auto-assigned clsid
  722.         }
  723.         if (!alwaysReg) {
  724.           strstream checkStrm;
  725.           NS_OCF::OcRegisterClass(regList, AppInstance, checkStrm, lang,
  726.                             "\001\002\006", 0, clsInfo);
  727.           if (NS_OCF::OcRegistryValidate(checkStrm) == 0)
  728.             continue;
  729.         }
  730.         if (debugStat) {
  731.           NS_OCF::OcRegisterClass(
  732.             regList, AppInstance, *strm, lang, 0, regAppName, regClsid);
  733.           if (debugStat == 1) {   // needs generated guid string
  734.             TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  735.             strcpy(guidStr, linkClsid);
  736.           }
  737.           NS_OCF::OcRegisterClass(
  738.             regList, AppInstance, *strm, lang, DocDebugFilter, regAppName,
  739.             regDebug);
  740.         }
  741.         else {
  742.           NS_OCF::OcRegisterClass(regList, AppInstance, *strm, lang, 0,
  743.                                   regAppName, clsInfo);
  744.         }
  745.         forceReg = true;
  746.       }
  747.     }
  748.     if (forceReg && !regFilename)
  749.       NS_OCF::OcRegistryUpdate(regStrm);
  750.     if (forceReg)
  751.       ::RegDeleteKey(TRegKey::ClassesRoot, "OcErr_RegServer");
  752.   }
  753.   catch (TXBase& xcpt) {
  754.     ::RegSetValue(TRegKey::ClassesRoot, "OcErr_RegServer", REG_SZ, AppClassId, 0);
  755.     if (!(Options & amQuietReg))
  756.       throw;
  757.   }
  758.   return;
  759. }
  760.  
  761. //
  762. //
  763. //
  764. void
  765. TAppDescriptor::UnregisterServer(TLangId, const char*)
  766. {
  767.   // Remove application and all type library info from registry
  768.   //
  769.   HKEY key;
  770.   char guidStr[40];
  771.   TRegItem debugItem = {"debugclsid", {guidStr}};
  772.   TRegItem* debugInfo = 0;              // init to no debug registration
  773.   if (AppProgId) {          // don't attempt unregister app if no progid reg key
  774.     if (DebugGuidOffset) {                // setup reg item for debug reg
  775.       TClassId debugClsid(AppClassId[DebugGuidOffset]);
  776.       strcpy(guidStr, debugClsid);
  777.       debugInfo = &debugItem;
  778.     }
  779.     NS_OCF::OcUnregisterClass(RegInfo, debugInfo);   // unregister app
  780.     if (LibGuidOffset) {
  781.       ::RegOpenKey(TRegKey::ClassesRoot, "TypeLib", &key);
  782.       ::RegDeleteKey(key, AppClassId[LibGuidOffset]);
  783.       ::RegCloseKey(key);
  784.     }
  785.     if (ClassCount) {
  786.       ::RegOpenKey(TRegKey::ClassesRoot, "Interface", &key);
  787.       for (int i= 0; i < ClassCount; i++)
  788.         ::RegDeleteKey(key, AppClassId[ClassList[i].GuidOffset]);
  789.       ::RegCloseKey(key);
  790.     }
  791.   }
  792.  
  793.   // Remove templates from registration file as needed
  794.   //
  795.   int linkGuidIndex = 0;
  796.   for (const TRegLink* link = LinkHead; link; link=link->GetNext()) {
  797.     TRegList& regList = link->GetRegList();
  798.     if (regList["progid"]) {
  799.       if (!regList["clsid"]) {      // check if GUID needs to be computed
  800.         TClassId linkClsid(GetLinkGuid(linkGuidIndex++));
  801.         strcpy(guidStr, linkClsid);
  802.         TRegItem clsItem = {"clsid", {guidStr}};
  803.         NS_OCF::OcUnregisterClass(regList, &clsItem);
  804.       }
  805.       else
  806.         NS_OCF::OcUnregisterClass(regList);
  807.     }
  808.   }
  809. }
  810.  
  811. //
  812. //
  813. //
  814. void
  815. TAppDescriptor::SetLangId(TLangId /*prevLang*/, const char* langIdStr)
  816. {
  817.   AppLang = ParseLangId(langIdStr);
  818. }
  819.  
  820. //
  821. //
  822. //
  823. void
  824. TAppDescriptor::MakeTypeLib(TLangId lang, const char* typeLibName)
  825. {
  826.   if (!ClassCount)
  827.     return;
  828.  
  829.   // Write the typelib file to <typeLibName>
  830.   //
  831.   char fullPath[_MAX_PATH];
  832.   char exeDrive[_MAX_DRIVE];
  833.   char exeDir  [_MAX_DIR];
  834.   char exeFName[_MAX_FNAME];
  835.   char exeExt  [_MAX_EXT];
  836.   char libDrive[_MAX_DRIVE];
  837.   char libDir  [_MAX_DIR];
  838.   char libFName[_MAX_FNAME];
  839.   char libExt  [_MAX_EXT];
  840.   ::GetModuleFileName(AppInstance, fullPath, sizeof(fullPath));
  841.   _splitpath(typeLibName? typeLibName:"", libDrive, libDir, libFName, libExt);
  842.   _splitpath(fullPath, exeDrive, exeDir, exeFName, exeExt);
  843.   _makepath (fullPath,
  844.              libDrive[0] ? libDrive : exeDrive,
  845.              libDir[0]   ? libDir   : exeDir,
  846.              libFName[0] ? libFName : exeFName,
  847.              libExt[0]   ? libExt   : "OLB");
  848.  
  849.   try {
  850.     WriteTypeLibrary(lang, fullPath);
  851.     ::RegDeleteKey(TRegKey::ClassesRoot, "OcErr_Typelib");
  852.   }
  853.   catch (TXOle&) {
  854.     ::RegSetValue(TRegKey::ClassesRoot, "OcErr_Typelib", REG_SZ, AppClassId, 0);
  855.     if (!(Options & amQuietReg))
  856.       throw;
  857.   }
  858. }
  859.  
  860. // NOTE: 'TAppDescriptor::WriteTypeLibrary' is implemented in the
  861. //        module TYPELIB.CPP
  862. //
  863.  
  864. //
  865. //
  866. //
  867. void
  868. TAppDescriptor::ProcessCmdLine(string& cmdLine)
  869. {
  870.   struct {
  871.     uint32 Flag;
  872.     char*  String;
  873.     void   (TAppDescriptor::*Action)(TLangId, const char*);
  874.   }
  875.   optionTbl[] = {
  876.     { amRegServer,    "RegServer",     &TAppDescriptor::RegisterServer },
  877.     { amUnregServer,  "UnregServer",   &TAppDescriptor::UnregisterServer },
  878.     { amAutomation,   "Automation",    0 },
  879.     { amEmbedding,    "Embedding",     0 },
  880.     { amLangId,       "Language",      &TAppDescriptor::SetLangId },
  881.     { amTypeLib,      "TypeLib",       &TAppDescriptor::MakeTypeLib },
  882.     { amNoRegValidate,"NoRegValidate", 0 },
  883.     { amQuietReg ,    "QuietReg",      0 },
  884.     { amDebug,        "Debug",         0 },
  885.     { amUnregServer,  "Unregister",    &TAppDescriptor::UnregisterServer },
  886.   };
  887.   const int optionTblCount = sizeof(optionTbl)/sizeof(optionTbl[0]);
  888.   TCmdLine cmd(cmdLine.c_str());
  889.  
  890.   while (cmd.Kind != TCmdLine::Done) {
  891.     switch (cmd.Kind) {
  892.       default: {
  893.         cmd.NextToken();        // ignore token, not one of ours
  894.         break;
  895.       }
  896.       case TCmdLine::Option: {
  897.         int i;
  898.         for (i = 0; i < optionTblCount; i++) {
  899.           if (strnicmp(cmd.Token, optionTbl[i].String, cmd.TokenLen) == 0) {
  900.             Options |= optionTbl[i].Flag;
  901.             cmd.NextToken(true);    // eat token & get next
  902.             if (cmd.Kind == TCmdLine::Value) {
  903.               string optionArg(cmd.Token, 0, cmd.TokenLen);
  904.               while (cmd.NextToken(true) == TCmdLine::Value)
  905.                 ; // eat token & get next (keep going if more Values are there)
  906.               if (optionTbl[i].Action)
  907.                 (this->*optionTbl[i].Action)(AppLang, optionArg.c_str());
  908.             }
  909.             else {
  910.               if (optionTbl[i].Action)
  911.                 (this->*optionTbl[i].Action)(AppLang, 0);
  912.             }
  913.             break; // out of for loop
  914.           }
  915.         }
  916.         if (i >= optionTblCount)
  917.           cmd.NextToken();        // ignore token, wasn't one of ours
  918.         break;
  919.       }
  920.     }
  921.   }
  922.   cmdLine = cmd.GetLine();
  923.  
  924.   // Set single use if this is an automated exe server
  925.   //
  926.   if ((Options & (amAutomation | amExeModule)) == (amAutomation | amExeModule))
  927.     Options |= amSingleUse;
  928.  
  929.   // Perform normal registry update if no other registry option was specified
  930.   //
  931.   if (!(Options & (amRegServer | amUnregServer | amNoRegValidate)))
  932.     RegisterServer(0);
  933. }
  934.  
  935. //
  936. //
  937. //
  938. static TLangId ParseLangId(const char* text)
  939. {
  940.   static char HexChar[] = "0123456789ABCDEF0123456789abcdef";
  941.   TLangId lang = 0;
  942.   unsigned char c;
  943.   char* pc;
  944.   while (text && (c = *text++) != 0) {
  945.     if ((pc = strchr(HexChar, c)) == 0)
  946.       return 0;   // illegal character
  947.     lang = TLangId((lang << 4) + (short(pc-HexChar) & 15));
  948.   }
  949.   return lang ? lang : TLocaleString::UserDefaultLangId;
  950. }
  951.  
  952. //
  953. //
  954. //
  955. void
  956. TAppDescriptor::MergeAutoClasses()
  957. {
  958.   int oldCount = ClassCount;
  959.   ClassCount = TAutoClass::ClassList.CountAutoClasses();
  960.   if (ClassCount) {
  961.  
  962.     // Allocated GUID for type Library
  963.     //
  964.     if (!LibGuidOffset)
  965.       LibGuidOffset = AppClassId.AllocId();
  966.  
  967.     TAutoClass::TAutoClassRef* oldList  = ClassList;
  968.     ClassList = new TAutoClass::TAutoClassRef[ClassCount];
  969.     TAutoClass::ClassList.MergeAutoClasses(ClassList);
  970.     TAutoClass::TAutoClassRef* ref = ClassList;
  971.     for (int count = ClassCount; count--; ref++) {
  972.       if (oldCount) {
  973.         ref->GuidOffset = oldList->GuidOffset;
  974.         oldCount--;
  975.         oldList++;
  976.       }
  977.       else {
  978.         ref->GuidOffset = AppClassId.AllocId();
  979.       }
  980.     }
  981.   }
  982. }
  983.  
  984.